/**
 * 文件名：@AbstractHandlerInfoResolver.java <br/>
 * 包名：cn.efunbox.afw.core.resolver <br/>
 * 项目名：afw-core <br/>
 * @author xtwin <br/>
 */
package cn.efunbox.afw.core.resolver;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import cn.efunbox.afw.core.AfwContext;
import cn.efunbox.afw.core.annotation.mvc.Bind;
import cn.efunbox.afw.core.annotation.mvc.Extract;
import cn.efunbox.afw.core.annotation.mvc.PostAction;
import cn.efunbox.afw.core.annotation.mvc.PreAction;
import cn.efunbox.afw.core.annotation.mvc.Result;
import cn.efunbox.afw.core.annotation.mvc.Template;
import cn.efunbox.afw.core.decoupling.HandlerHolder;
import cn.efunbox.afw.core.exception.AfwRuntimeException;
import cn.efunbox.afw.core.invocation.Invoker;
import cn.efunbox.afw.core.invocation.ReflectMethodInvoker;
import cn.efunbox.afw.core.mvc.HandlerInfo;
import cn.efunbox.afw.core.mvc.context.Context;
import cn.efunbox.afw.core.mvc.template.Templator;
import cn.efunbox.afw.core.util.StringUtil;

/**
 * 类名：AbstractHandlerInfoResolver  <br />
 *
 * 功能：HandlerInfo解析器基础实现
 *
 * @author xtwin <br />
 * 创建时间：2015年12月9日 上午10:48:25  <br />
 * @version 2015年12月9日
 */
public abstract class AbstractHandlerInfoResolver implements HandlerInfoResolver, ApplicationContextAware {
	
	// 数据容器
	private Map<Object, HandlerInfo> cacheMap = null;
	
	// 模板解析器
	private Resolver<Templator> templatorResolver;
	
	// 默认结果类型
	private String resultType;

	// spring上下文
	protected ApplicationContext ctx;
	
	// 缓存开关，默认为开启
	private boolean cacheEnable = true;
	
	// 开启懒加载
	private boolean lazy;
	
	// 线程缓存中的key前缀
	private static final String THREAD_LOCAL_KEY_PREFIX = "HANDLERINFO__";
	
	/**
	 * 
	 * 功能：执行初始化相关工作 <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 下午12:17:41 <br/>
	 */
	public void init() {
		if (cacheEnable) {
			if (lazy) {
				/**
				 *  懒加载时需要动态更新缓存，此时使用并发map
				 *  也可以考虑使用读写锁的方式，此时先不使用
				 */
				cacheMap = new ConcurrentHashMap<Object, HandlerInfo>();
			} else {
				cacheMap = new HashMap<Object, HandlerInfo>();
			}
		}
	}
	
	/**
	 * 功能: <br/>
	 * 
	 * 重写：xtwin <br/>
	 * 
	 * @version ：2015年12月9日 下午12:01:22<br/>
	 * 
	 * @param handler
	 * @throws Exception <br/>
	 * @see cn.efunbox.afw.core.resolver.HandlerInfoResolver#registe(java.lang.Object)
	 */
	@Override
	public void registe(Object handler) throws Exception {
		if (cacheEnable && ! lazy) {
			// 在开启缓存且禁用懒加载时，进行注册处理
			cacheMap.put(getCacheKey(handler), create(AfwContext.getContext(), handler));
		}
			
	}

	/**
	 * 
	 * 功能: <br/>
	 * 
	 * 重写：xtwin <br/>
	 * 
	 * @version ：2015年12月9日 下午12:33:00<br/>
	 * 
	 * @param handler
	 * @return
	 * @throws Exception <br/>
	 * @see cn.efunbox.afw.core.resolver.HandlerInfoResolver#resolve(java.lang.Object)
	 */
	@Override
	public HandlerInfo resolve(Object handler) throws Exception {

		// 先解析出处理器
		//Object handler = resolveHandler(context);
		
		Context context = AfwContext.getContext();
		
		// 取得缓存时，使用的key
		Object key = getCacheKey(handler);
		HandlerInfo info = null;
		if (cacheEnable) {
			// 开启缓存时，先尝试从缓存中提取
			if (null==cacheMap){
				init();
			}
			// 查找缓存
			info = cacheMap.get(key);
			
			if (null == info && lazy) {
				// 若当前缓存中不存在，且开启了懒加载，则执行创建并更新到缓存中
				info = create(context, handler);
				
				// 更新到缓存
				cacheMap.put(key, info);
			}
		} else {
			/**
			 *  未开启系统缓存
			 *  先从线程缓存中提取，防止在一次请求中多次执行创建，浪费资源
			 *  这里不考虑多线程加锁，因为即使多线程同时操作创建了多个对象，也不影响
			 */
			String _tmp = THREAD_LOCAL_KEY_PREFIX + key;
			info = AfwContext.getValue(_tmp);
			if (null == info) {
				info = create(context, handler);
				
				// 更新到线程缓存中，当前线程下次使用
				AfwContext.setValue(_tmp, info);
			}
		}
		
		/*// 解析出目标方法对象
		Method method = resolveMethod(context, handler);
		
		// 解析出模板
		Templator templator = resolveTemplator(context, handler, method);
		
		// 创建并返回对象
		return createHandlerInfo(
				handler, 
				resolvePreInvokers(context, handler, method), 
				resolvePostInvokers(context, handler, method), 
				templator, 
				resolveResultType(context, handler, method, templator), 
				resolveExtract(context, handler, method), 
				resolveBinds(context, handler, method)
			);*/
		
		return info;
	}
	
	/**
	 * 
	 * 功能：取得缓存时使用的key <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 下午12:08:38 <br/>
	 */
	protected Object getCacheKey(Object handler) {
		return handler.toString();
	}
	
	/**
	 * 
	 * 功能：创建 <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 下午12:05:58 <br/>
	 */
	protected HandlerInfo create(Context context, Object handler) throws Exception {
		
		// 解析出目标方法对象
		Method method = resolveMethod(context, handler);
		
		// 解析出模板
		Templator templator = resolveTemplator(context, handler, method);
		
		// 创建并返回对象
		return createHandlerInfo(
				handler, 
				resolvePreInvokers(context, handler, method), 
				resolvePostInvokers(context, handler, method), 
				templator, 
				resolveResultType(context, handler, method, templator), 
				resolveExtract(context, handler, method), 
				resolveBinds(context, handler, method),
				resolveResult(context, handler, method)
			);
	}
	
	/**
	 * 功能： <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 下午1:58:28 <br/>
	 */
	protected Result resolveResult(Context context, Object handler, Method method) {
		return method.getAnnotation(Result.class);
	}

	/**
	 * 功能：解析处理器 <br/>
	 * 
	 * 		默认实现为从HandlerHolder中提取
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 上午10:54:19 <br/>
	 */
	protected Object resolveHandler(Context context) throws Exception {
		return context instanceof HandlerHolder ? ((HandlerHolder) context).getHandler() : null;
	}
	
	/**
	 * 功能：解析出处理器要执行的方法对象 <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 上午11:03:30 <br/>
	 */
	protected abstract Method resolveMethod(Context context, Object handler) throws Exception;
	
	/**
	 * 
	 * 功能：解析模板信息 <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 上午10:55:04 <br/>
	 */
	protected Templator resolveTemplator(Context context, Object handler, Method method) throws Exception {
		// 处理template注解
		Template template = method.getAnnotation(Template.class);
		
		// 获取模板名称
		String name = null;
		if (null != template) {
			// 取出配置的模板名称
			name = StringUtil.emptyAdjust(template.name());
		}
		
		// 解析出模板
		return templatorResolver.resolve(name);
	}
	
	/**
	 * 
	 * 功能：解析前置处理器信息 <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 上午10:57:53 <br/>
	 */
	protected Invoker[] resolvePreInvokers(Context context, Object handler, Method method) throws Exception {
		PreAction[] pas = method.getAnnotationsByType(PreAction.class);
		
		if (null != pas && pas.length > 0) {
			List<Invoker> invokers = new ArrayList<Invoker>();
			
			for (PreAction pa : pas) {
				resolveInvoker(invokers, ctx, pa.value(), pa.name(), pa.type(), pa.method(), handler, method);
			}
			
			// 转为数组返回
			return invokers.toArray(new Invoker[invokers.size()]);
		}
		
		return null;
	}
	
	/**
	 * 功能：解析后置处理器信息 <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 上午10:57:39 <br/>
	 */
	protected Invoker[] resolvePostInvokers(Context context, Object handler, Method method) throws Exception {
		PostAction[] pas = method.getAnnotationsByType(PostAction.class);
		
		if (null != pas && pas.length > 0) {
			List<Invoker> invokers = new ArrayList<Invoker>();
			
			for (PostAction pa : pas) {
				resolveInvoker(invokers, ctx, pa.value(), pa.name(), pa.type(), pa.method(), handler, method);
			}
			
			// 转为数组返回
			return invokers.toArray(new Invoker[invokers.size()]);
		}
		
		return null;
	}
	
	/**
	 * 功能：解析默认结果类型信息 <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 上午10:57:19 <br/>
	 */
	protected String resolveResultType(Context context, Object handler, Method method, Templator templator) throws Exception {
		String resultType = templator.getResultType();
		
		if (null == resultType) {
			resultType = this.resultType;
		}
		
		return resultType;
	}
	
	/**
	 * 功能：解析提取信息 <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 上午10:57:06 <br/>
	 */
	protected String[] resolveExtract(Context context, Object handler, Method method) throws Exception {
		Extract extract = method.getAnnotation(Extract.class);
		
		return null != extract ? extract.value() : null;
	}
	
	/**
	 * 功能：解析绑定信息 <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 上午10:56:51 <br/>
	 */
	protected Bind[] resolveBinds(Context context, Object handler, Method method) throws Exception {
		return method.getAnnotationsByType(Bind.class);
	}
	
	/**
	 * 
	 * 功能： <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月3日 下午2:28:08 <br/>
	 */
	protected void resolveInvoker(List<Invoker> invokers, ApplicationContext ctx, String[] exps, String beanName, Class<?> type, String mname, Object handler, Method method) throws Exception {
		Object bean = null;
		
		// 优先按name方式处理
		if (! StringUtil.isEmpty(beanName)) {
			bean = ctx.getBean(beanName);
		} else if (Void.class != type) {
			bean = ctx.getBean(type);
		}
		
		if (null != bean) {
			invokers.add(new ReflectMethodInvoker(bean, bean.getClass().getMethod(StringUtil.isEmpty(mname) ? "execute" : mname, Context.class)));
		} else {
			if (null == exps || exps.length == 0) {
				throw new AfwRuntimeException("illegal.preAction.definition.on.method : " + method);
			}
			
			/**
			 * 在表达式中可以使用！指定方法名，使用c:开头指明当前使用的是类名，如：
			 * 	testAction
			 * 		代表bean id为testAction的bean的execute方法
			 * 	c:testAction
			 * 		代表bean的类全名为testAction的execute方法
			 * 	testAction!update
			 * 		代表bean id为testAction的bean的update方法
			 * 	c:testAction!update
			 * 		代表bean的类全名为testAction的update方法
			 */
			for (String exp : exps) {
				
				String _mname = "execute";
				
				int index = exp.indexOf('!');
				
				if (index != -1) {
					_mname = exp.substring(index + 1);
					
					exp = exp.substring(0, index);
				}
				
				if (exp.startsWith("c:")) {
					// 类名
					bean = ctx.getBean(Class.forName(exp.substring(2)));
				}
				
				invokers.add(new ReflectMethodInvoker(bean, bean.getClass().getMethod(_mname, Context.class)));
			}
		}
	}
	
	/**
	 * 
	 * 功能：创建处理器信息对象 <br/>
	 *
	 * @author xtwin <br/>
	 * @version 2015年12月9日 上午10:49:45 <br/>
	 */
	protected HandlerInfo createHandlerInfo(
			final Object handler, 
			final Invoker[] preInvokers, 
			final Invoker[] postInvokers, 
			final Templator templator, 
			final String resultType,
			final String[] extract, 
			final Bind[] binds,
			final Result result) {
		
		// 创建一个内部实现的不可修改的对象
		return new HandlerInfo() {
			@Override
			public Templator getTemplator() {
				return templator;
			}
			
			@Override
			public String getResultType() {
				return resultType;
			}
			
			@Override
			public Invoker[] getPreInvokers() {
				return preInvokers;
			}
			
			@Override
			public Invoker[] getPostInvokers() {
				return postInvokers;
			}
			
			@SuppressWarnings("unchecked")
			@Override
			public <T> T getHandler() {
				return (T) handler;
			}
			
			@Override
			public String[] getExtract() {
				return extract;
			}
			
			@Override
			public Bind[] getBinds() {
				return binds;
			}

			@Override
			public Result getResult() {
				return result;
			}
		};
	}
	
	/**
	 * 功能: <br/>
	 * 
	 * 重写：xtwin <br/>
	 * 
	 * @version ：2015年12月9日 上午11:10:15<br/>
	 *
	 * @param ctx
	 * @throws BeansException <br/>
	 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
	 */
	@Override
	public void setApplicationContext(ApplicationContext ctx) throws BeansException {
		this.ctx = ctx;
	}

	/**
	 * @version 2015年12月9日-下午2:07:35
	 */
	public void setTemplatorResolver(Resolver<Templator> templatorResolver) {
		this.templatorResolver = templatorResolver;
	}

	/**
	 * @version 2015年12月9日-下午2:07:35
	 */
	public void setResultType(String resultType) {
		this.resultType = resultType;
	}

	/**
	 * @version 2015年12月9日-下午2:07:35
	 */
	public void setCtx(ApplicationContext ctx) {
		this.ctx = ctx;
	}

	/**
	 * @version 2015年12月9日-下午2:07:35
	 */
	public void setCacheEnable(boolean cacheEnable) {
		this.cacheEnable = cacheEnable;
	}

	/**
	 * @version 2015年12月9日-下午2:07:35
	 */
	public void setLazy(boolean lazy) {
		this.lazy = lazy;
	}
}
